# -*- coding: utf-8 -*-

import os
import sys
from contextlib import closing
import math
import jinja2
import time
import werkzeug.utils
import datetime
import openerp
import simplejson
from openerp import http
from openerp.http import request
from openerp.modules.registry import RegistryManager
from reportlab.graphics.barcode import createBarcodeDrawing
from openerp.addons.wechat.enterprise import WxApi, WxApplication, WxTextResponse, WxNewsResponse, WxArticle, WxLink
from openerp.addons.website_mshop.pools import ModelPool, CursorProxy, common_functions, PageProxy, _slug
from openerp.addons.dftg_weixin.application.application_test import WxAppCropTest
import pytz


ISODATEFORMAT = '%Y-%m-%d'
ISODATETIMEFORMAT = "%Y-%m-%d %H:%M:%S"
SUPERUSER_ID = 1

if hasattr(sys, 'frozen'):
    # When running on compiled windows binary, we don't have access to package loader.
    path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', 'html'))
    loader = jinja2.FileSystemLoader(path)
else:
    loader = jinja2.PackageLoader('openerp.addons.dftg_weixin', "html")

env = jinja2.Environment('<%', '%>', '${', '}', '%', loader=loader, autoescape=True)


class WeixinAppTestController(http.Controller):
    weixin_app = None

    def __init__(self):
        env.globals['_pool'] = ModelPool()
        env.globals['_cr'] = CursorProxy()
        env.globals['_page'] = PageProxy()
        env.globals['_slug'] = _slug
        env.globals.update(common_functions)
        env.filters['tojson'] = simplejson.dumps
        self.weixin_app = WxAppCropTest()

    # 微信回调入口网址
    @http.route('/weixin/app/test', auth='public')
    def weixin(self, **kw):
        result = self.weixin_app.process(request.httprequest.args, request.httprequest.data)
        return result

    @http.route('/weixin/delivery/update_location', auth='public')
    def update_location(self, user_id, latitude, longitude, speed, accuracy, **kw):
        cr, context, pool = request.cr, request.context, request.registry
        picking_ids = pool.get('stock.picking').search(cr, SUPERUSER_ID,
                                                       [('delivery_user_id', '=', int(user_id)), ('state', '=', 'done'),
                                                        ('delivery_state', '=', 'shipping')], context=context)

        for picking_id in picking_ids:
            pool.get('stock.position').create(cr, SUPERUSER_ID, {
                'picking_id': picking_id,
                'user_id': int(user_id),
                'latitude': float(latitude),
                'longitude': float(longitude),
                'speed': float(speed),
                'accuracy': float(accuracy),
            }, context=context)

        cr.commit()
        return 'OK'

    @http.route('/weixin/delivery/submit', auth='public')
    def delivery_submit(self, picking_ids, user_id, **kw):
        cr, context, pool = request.cr, request.context, request.registry
        if picking_ids and user_id:
            picking_ids, user_id = map(int, simplejson.loads(picking_ids)), int(user_id)
            for picking in pool.get('stock.picking').browse(cr, SUPERUSER_ID, picking_ids, context=context):
                if picking.picking_type_id and picking.picking_type_id.code == 'outgoing' and picking.delivery_state != 'delivery_done':
                    cr.execute('''
                        UPDATE stock_picking set delivery_user_id = %s, delivery_state = 'shipping', delivery_start_time = (now() at time zone 'UTC') WHERE id = %s
                    ''', (user_id, picking.id))
                    if picking.state == 'assigned':
                        picking.do_picking_done()
                    cr.commit()

    @http.route('/weixin/delivery/get_pickings_by_search', auth='public')
    def get_pickings_by_search(self, search_type, search_word, **kw):
        cr, context, pool = request.cr, request.context, request.registry
        return request.make_response(simplejson.dumps(
            pool.get('stock.picking').get_pickings_by_search(cr, SUPERUSER_ID, search_type, search_word,
                                                             context=context)
        ))

    @http.route('/weixin/delivery/get_pickings', auth='public')
    def get_pickings(self, user_id, **kw):
        cr, context, pool = request.cr, request.context, request.registry
        return request.make_response(simplejson.dumps(
            pool.get('stock.picking').get_pickings_by_user(cr, SUPERUSER_ID, user_id, context=context)
        ))

    @http.route('/weixin/delivery/change_user', auth='public')
    def change_user(self, picking_id, user_id, **lw):
        cr, context, pool = request.cr, request.context, request.registry
        pool.get('stock.picking').write(cr, SUPERUSER_ID, int(picking_id), {'delivery_user_id': int(user_id),
                                                                            'delivery_state': 'shipping',
                                                                            'delivery_start_time': openerp.osv.fields.datetime.now(
                                                                                self, cr, SUPERUSER_ID)},
                                        context=context)

    @http.route('/weixin/delivery/get_lines', auth='public')
    def get_lines(self, picking_id, **kw):
        cr, context, pool = request.cr, request.context, request.registry

        picking = pool.get('stock.picking').browse(cr, SUPERUSER_ID, int(picking_id), context=context)
        res = []
        for line in picking.move_lines:
            res.append({
                'product_id': line.product_id.id,
                'product_name': line.product_id.name,
                'product_qty': line.product_qty,
            })

        return request.make_response(simplejson.dumps(res))

    @http.route('/weixin/delivery_in/action_done', auth='public', website=True)
    def delivery_action_done(self, move_id, **kw):
        cr, context, pool = request.cr, request.context, request.registry
        if move_id:
            move_id = int(move_id)
            pool.get('stock.move').action_done(cr, SUPERUSER_ID, move_id, context=context)

    @http.route('/weixin/delivery_in/get_moves', auth='public', website=True)
    def delivery_get_moves(self, product_id, **kw):
        cr, context, pool = request.cr, request.context, request.registry
        if product_id:
            product_id = int(product_id)
            move_obj = pool.get('stock.move')
            product_obj = pool.get('product.product')
            product = product_obj.browse(cr, SUPERUSER_ID, product_id, context=context)

            move_ids = move_obj.search(cr, SUPERUSER_ID, [('product_id', '=', product_id),
                                                          ('state', '=', 'assigned'),
                                                          ('picking_id.picking_type_id.code', '=', 'incoming')],
                                       context=context)

            res = {
                'active_length': 0,
                'product': {
                    'id': product.id,
                    'name': product.name,
                    'description': product.description_sale or '',
                    'uom': product.uom_id.name,
                },
                'moves': []
            }
            for move in move_obj.browse(cr, SUPERUSER_ID, move_ids, context=context):
                res['moves'].append({
                    # 'product_id': move.product_id.id,
                    # 'product_name': move.product_id.name,
                    'id': move.id,
                    'delete': False,
                    'product_qty': move.product_qty,
                    'picking_name': move.picking_id.name,
                })

            res['active_length'] = len(res['moves'])
            return request.make_response(simplejson.dumps(res))

        return {}

    def _get_product_incoming(self):
        request.cr.execute('''
                SELECT COUNT(*) FROM stock_move sm
                LEFT JOIN stock_picking sp ON sm.picking_id = sp.id
                    LEFT JOIN stock_picking_type spt ON sp.picking_type_id = spt.id

                WHERE sm.state = 'assigned'
                  AND spt.code = 'incoming'
            ''')

        try:
            return request.cr.fetchall()[0][0]
        except IndexError:
            return 0

    def matching_move(self, move, search_type, search_word):
        def _check_product_name():
            try:
                move.get('product_name', '').lower().index(search_word.lower())
            except ValueError:
                return False

            return True

        def _check_picking_name():
            try:
                move.get('picking_name', '').lower().index(search_word.lower())
            except ValueError:
                return False

            return True

        if search_type == 'product_name':
            return _check_product_name()

        if search_type == 'picking_name':
            return _check_picking_name()

        if search_type == 'all':
            return _check_product_name() or _check_picking_name()

        return False

    @http.route('/weixin/delivery_in_list/get_product_by_ean13', auth='public', website=True)
    def delivery_in_list_get_product_by_ean13(self, ean13='', **kw):
        cr, context, pool = request.cr, request.context, request.registry
        if ean13.startswith('EAN_13'):
            product_ids = pool.get('product.product').search(cr, SUPERUSER_ID,
                                                             [('ean13', '=', ean13.partition(',')[2])], context=context)
            if product_ids:
                move_ids = pool.get('stock.move').search(cr, SUPERUSER_ID, [('product_id', '=', product_ids[0]),
                                                                            ('state', '=', 'assigned'), (
                                                                                'picking_id.picking_type_id.code', '=',
                                                                                'incoming')], context=context)
                if move_ids:
                    response = {'res': 'success', 'product_id': product_ids[0]}
                else:
                    product_name = pool.get('product.product').read(cr, SUPERUSER_ID, product_ids[0], ['name'],
                                                                    context=context).get('name', '')
                    response = {'res': 'error', 'message': u'不存在产品"%s"的入库' % product_name}
            else:
                response = {'res': 'error', 'message': u'当前码"%s",没有找到相应的产品，请重新扫码' % ean13.partition(',')[2]}
        else:
            response = {'res': 'error', 'message': u'错误的码"%s"，不是产品的ean13码' % ean13}

        return request.make_response(simplejson.dumps(response))

    @http.route('/weixin/delivery_in_list/get_current_length', auth='public', website=True)
    def delivery_in_list_get_current_length(self, search_type='all', search_word='', **kw):
        extra_domain = ''
        if search_type == 'product_name' and search_word:
            extra_domain += " AND pt.name ILIKE '%%%s%%'" % search_word

        if search_type == 'picking_name' and search_word:
            extra_domain += " AND sp.name ILIKE '%%%s%%'" % search_word

        if search_type == 'all' and search_word:
            extra_domain += " AND (sp.name ILIKE '%%%s%%' OR pt.name ILIKE '%%%s%%')" % (search_word, search_word)

        request.cr.execute('''
                SELECT COUNT(*) FROM stock_move sm
                LEFT JOIN stock_picking sp ON sm.picking_id = sp.id
                    LEFT JOIN stock_picking_type spt ON sp.picking_type_id = spt.id

                LEFT JOIN product_product pp ON sm.product_id = pp.id
                    LEFT JOIN product_template pt ON pp.product_tmpl_id = pt.id

                WHERE sm.state = 'assigned'
                  AND spt.code = 'incoming'
                  %s
            ''' % extra_domain)

        try:
            count = request.cr.fetchall()[0][0]
        except IndexError:
            count = 0

        return request.make_response(simplejson.dumps({'current_length': count}))

    @http.route('/weixin/delivery_in_list/get_stocks', auth='public', website=True)
    def delivery_in_list_get_stocks(self):
        cr, context, pool = request.cr, request.context, request.registry

        res = pool.get('stock.location').search_read(cr, SUPERUSER_ID,
                                                     [('usage', '=', 'internal')],
                                                     ['name'], context=context)

        return request.make_response(simplejson.dumps(res))

    @http.route('/weixin/delivery_in_list/change_location', auth='public', website=True)
    def delivery_in_list_change_location(self, move_id, location_id):
        cr, context, pool = request.cr, request.context, request.registry

        pool.get('stock.move').write(cr, SUPERUSER_ID, int(move_id),
                                     {'location_dest_id': int(location_id)},
                                     context=context)

    @http.route('/weixin/delivery_in_list/get_items', auth='public', website=True)
    def delivery_in_list_get_items(self, current_items, numbers, orderby, direction, search_type='all', search_word='',
                                   **kw):
        current_items, numbers, active_length = int(current_items), int(numbers), 0

        res = []
        order_by = 'product_name'
        if orderby == 'product_name':
            order_by = 'pt.name'
        elif orderby == 'picking_name':
            order_by = 'sp.name'
        elif order_by == 'product_qty':
            order_by = 'm.product_qty'

        if direction == 'up':
            order_by += ' desc'

        while active_length < numbers:
            request.cr.execute('''
                SELECT m.id AS id,
                       location.name as location,
                       pp.id as product_id,
                       pt.name as product_name,
                       it.value as product_uom_translation,
                       pu.name as product_uom,
                       m.product_qty as product_qty,
                       sp.name as picking_name,
                       true as visible
                FROM stock_move m
                LEFT JOIN stock_picking sp ON m.picking_id = sp.id
                    LEFT JOIN stock_picking_type spt ON sp.picking_type_id = spt.id
                LEFT JOIN product_product pp ON m.product_id = pp.id
                    LEFT JOIN product_template pt ON pp.product_tmpl_id = pt.id
                    LEFT JOIN product_uom pu ON pt.uom_id = pu.id
                        LEFT JOIN ir_translation it ON pu.id = it.res_id AND pu.name = it.src
                LEFT JOIN stock_location location ON m.location_dest_id = location.id

                WHERE m.state = 'assigned'
                  AND spt.code = 'incoming'

                ORDER BY %s, id OFFSET %s LIMIT %s
                ''' % (order_by, current_items, numbers * 2))

            moves = request.cr.dictfetchall()
            for move in moves:
                if self.matching_move(move, search_type, search_word):
                    active_length += 1

            res.extend(moves)

            current_items += len(moves)
            # 说明已经取不到数据了
            if len(moves) < numbers * 2:
                break

        return request.make_response(simplejson.dumps({'current_items': current_items, 'res': res}))

    @http.route('/weixin/delivery_in_list', auth='public', website=True)
    def delivery_in_list(self, **kw):
        cr, uid, context, pool = request.cr, request.uid, request.context, request.registry
        template = env.get_template('delivery_in_list.html')

        sgin_message = self.weixin_app.get_jsapi_signature(cr, uid, pool, context)
        sgin_message.update({
            'max_items': self._get_product_incoming(),
            'is_warehouse_user': pool.get('res.users').has_group(cr, uid, 'stock.group_stock_user'),
        })

        return template.render(sgin_message)

    def _get_stock_max_items(self, location_id):
        request.cr.execute('''
            SELECT COUNT(*)
            FROM product_product pp

            LEFT JOIN (
                SELECT sq.product_id AS product_id,
                       sum(sq.qty) AS product_qty
                FROM stock_quant sq
                WHERE location_id = %s
                GROUP BY sq.product_id) pq ON pp.id = pq.product_id

            LEFT JOIN (
                SELECT sm.product_id AS product_id,
                        sum(CASE WHEN sl.usage = 'internal' THEN sm.product_uom_qty ELSE 0 END) AS outgoing_qty,
                        sum(CASE WHEN sld.usage = 'internal' THEN sm.product_uom_qty ELSE 0 END) AS incoming_qty
                FROM stock_move sm
                LEFT JOIN stock_location sl ON sm.location_id = sl.id
                LEFT JOIN stock_location sld ON sm.location_dest_id = sld.id
                WHERE sm.state not in ('done', 'draft', 'cancel')
                  AND sl.usage != sld.usage
                  AND (sl.usage = 'internal' OR sld.usage = 'internal')

                GROUP BY sm.product_id) qty ON qty.product_id = pp.id

            WHERE pq.product_qty > 0 or qty.outgoing_qty > 0 or qty.incoming_qty > 0

            ''' % location_id)

        try:
            return request.cr.fetchall()[0][0]
        except IndexError:
            return 0

    @http.route('/weixin/product_stock/get_current_length', auth='public', website=True)
    def product_stock_get_current_length(self, location_id, search_word, **kw):
        request.cr.execute('''
                SELECT COUNT(*) FROM (
                    SELECT sq.product_id FROM stock_quant sq
                    LEFT JOIN product_product pp ON sq.product_id = pp.id
                        LEFT JOIN product_template pt ON pp.product_tmpl_id = pt.id
                    WHERE sq.location_id = %s AND (pp.default_code ILIKE '%%%s%%' OR pt.name ILIKE '%%%s%%')
                    GROUP BY product_id) s
            ''' % (location_id, search_word, search_word))

        try:
            count = request.cr.fetchall()[0][0]
        except IndexError:
            count = 0

        return request.make_response(simplejson.dumps({'current_length': count}))

    @http.route('/weixin/product_stock/get_items', auth='public', website=True)
    def product_stock_get_items(self, search_word, current_items, numbers, orderby, direction, location_id,
                                get_max_items, **kw):
        cr, context, pool = request.cr, request.context, request.registry
        current_items, numbers, active_length = int(current_items), int(numbers), 0
        search_word = search_word.lower()

        res = []

        if direction == 'up':
            orderby += ' desc'

        while active_length < numbers:
            request.cr.execute('''
                SELECT pp.id AS product_id,
                        pp.default_code AS default_code,
                        pt.name AS product_name,
                        pu.name AS product_uom,
                        it.value AS product_uom_translation,
                        pq.product_qty AS product_qty,
                        qty.outgoing_qty AS outgoing_qty,
                        qty.incoming_qty AS incoming_qty,
                        true AS visible

                FROM product_product pp

                LEFT JOIN (
                    SELECT sq.product_id AS product_id,
                           sum(sq.qty) AS product_qty
                    FROM stock_quant sq
                    WHERE location_id = %s
                    GROUP BY sq.product_id) pq ON pp.id = pq.product_id

                LEFT JOIN (
                    SELECT sm.product_id AS product_id,
                            sum(CASE WHEN sl.usage = 'internal' THEN sm.product_uom_qty ELSE 0 END) AS outgoing_qty,
                            sum(CASE WHEN sld.usage = 'internal' THEN sm.product_uom_qty ELSE 0 END) AS incoming_qty
                    FROM stock_move sm
                    LEFT JOIN stock_location sl ON sm.location_id = sl.id
                    LEFT JOIN stock_location sld ON sm.location_dest_id = sld.id
                    WHERE sm.state not in ('done', 'draft', 'cancel')
                      AND sl.usage != sld.usage
                      AND (sl.usage = 'internal' OR sld.usage = 'internal')

                    GROUP BY sm.product_id) qty ON qty.product_id = pp.id

                LEFT JOIN product_template pt ON pp.product_tmpl_id = pt.id
                    LEFT JOIN product_uom pu ON pt.uom_id = pu.id
                        LEFT JOIN ir_translation it ON pu.id = it.res_id AND pu.name = it.src

                WHERE pq.product_qty > 0 or qty.outgoing_qty > 0 or qty.incoming_qty > 0

                ORDER BY %s, product_id OFFSET %s LIMIT %s

                ''' % (location_id, orderby, current_items, numbers * 2))

            quants = request.cr.dictfetchall()
            for quant in quants:
                if search_word in quant.get('product_name', '').lower() or \
                        search_word in quant.get('default_code', '').lower():
                    active_length += 1

            res.extend(quants)

            current_items += len(quants)
            # 说明已经取不到数据了
            if len(quants) < numbers * 2:
                break

        response = {'current_items': current_items, 'res': res}
        if get_max_items == 'true':
            response.update({'max_items': self._get_stock_max_items(location_id)})

        return request.make_response(simplejson.dumps(response))

    @http.route('/weixin/product_stock', auth='public', website=True)
    def product_stock(self, **kw):
        cr, context, pool = request.cr, request.context, request.registry
        location_ids = pool.get('stock.location').search_read(cr, SUPERUSER_ID, [('usage', '=', 'internal')],
                                                              ['id', 'name'], context=context)
        if location_ids:
            kw.update({'location_ids': simplejson.dumps(location_ids)})
        else:
            raise IndexError(u'错误, 系统中没有定义最基础的库位信息')

        template = env.get_template('product_stock.html')
        return template.render(kw)

    @http.route('/weixin/delivery_in', auth='public', website=True)
    def delivery_in(self, product_id, **kw):
        template = env.get_template('delivery_in.html')
        if product_id:
            kw.update({'product_id': int(product_id)})

        return template.render(kw)

    @http.route('/weixin/delivery/success', auth='public', website=True)
    def delivery_success(self, picking_id, **kw):
        template = env.get_template('delivery_success.html')
        if picking_id:
            kw.update({'picking_id': int(picking_id)})

        return template.render(kw)

    @http.route('/weixin/delivery/error', auth='public', website=True)
    def delivery_error(self, picking_id, user_id, **kw):
        template = env.get_template('delivery_error.html')
        if picking_id:
            kw.update({'picking_id': int(picking_id)})

        if user_id:
            kw.update({'user_id': int(user_id)})

        return template.render(kw)

    @http.route('/weixin/delivery/list', auth='public', website=True)
    def delivery_list(self, user_id=None, **kw):
        cr, uid, context, pool = request.cr, request.uid, request.context, request.registry
        template = env.get_template('delivery_list.html')

        sgin_message = self.weixin_app.get_jsapi_signature(cr, uid, pool, context)

        return template.render(sgin_message)

    @http.route('/weixin/delivery/picking_done', auth='public')
    def picking_done(self, picking_ids, **kw):
        cr, context, pool = request.cr, request.context, request.registry
        picking_ids = simplejson.loads(picking_ids)

        pool.get('stock.picking').write(cr, SUPERUSER_ID, picking_ids, {'delivery_state': 'delivery_done',
                                                                        'delivery_done_time': openerp.osv.fields.datetime.now(
                                                                            self, cr, SUPERUSER_ID)}, context=context)

    # @http.route('/weixin/mshop', auth='public')
    # def weixin_mshop()

    # 微信用户绑定
    # 开启微信二次验证，让用户确认一下绑定的partner或者联系人
    @http.route('/weixin/binding', auth='public')
    def binding(self, **kw):
        cr, db_name, user_id = request.cr, request.session.db, request.session.user_id
        oauth_uid = request.session.oauth_uid
        if not oauth_uid and not 'agentid' in kw:
            url = self.weixin_app.oauth_authorize_redirect_url(db_name, request.httprequest.host + '/weixin/binding',
                                                               {})
            return werkzeug.utils.redirect(url)
        contacts = False
        if user_id:
            contacts_obj = openerp.registry(db_name)['weixin.contacts']
            try:
                contacts = contacts_obj.browse(cr, SUPERUSER_ID, int(user_id))
            except ValueError:
                template = env.get_template('no_partner.html')
                return template.render({})

            if contacts.exists():
                if not contacts.partner_id:
                    template = env.get_template('no_partner.html')
                    return template.render({})

        template = env.get_template('binding.html')
        return template.render({
            # 'session': request.session,
            'user_id': user_id,
            'partner': contacts and contacts.partner_id or False,
            'contacts': contacts and contacts.contacts_id or False,
            'user': contacts and contacts.odoo_user_id or False,
            'attention': contacts and contacts.is_follow or False,
        })

    @http.route('/weixin/old/binding', auth='public')
    def binding_old(self, **kw):
        cr = request.cr
        db_name = request.session.db
        # 微信企业号用手机号码作为uid
        mobile = kw.get('mobile')  # 临时从mobile参数中取得手机号码
        partner_id = None
        address_id = None
        user_id = None
        partner = None
        address_contacts = None
        user = None
        if mobile:
            # 优先用手机查找多地址联系人
            address_obj = openerp.registry(db_name)['customer.address']
            address_ids = address_obj.search(cr, SUPERUSER_ID, [('mobile_number', '=', mobile)], limit=1)
            if address_ids:
                address_id = address_ids[0]
                address_contacts = address_obj.browse(cr, SUPERUSER_ID, address_id)
                partner = address_contacts.partner_id
                partner_id = partner.id
            # 如果找不到多地址联系人，则直接查找partner
            else:
                partner_obj = openerp.registry(db_name)['res.partner']
                partner_ids = partner_obj.search(cr, SUPERUSER_ID, [('mobile', '=', mobile)], limit=1)
                if partner_ids:
                    partner_id = partner_ids[0]
                    partner = partner_obj.browse(cr, SUPERUSER_ID, partner_id)

            # 如果存在对应的partner，取得相关的user
            if partner_id:
                users_obj = openerp.registry(db_name)['res.users']
                user_ids = users_obj.search(cr, SUPERUSER_ID, [('partner_id', '=', partner_id)])
                if user_ids:
                    user_id = user_ids[0]
                    user = users_obj.browse(cr, SUPERUSER_ID, user_id)

            else:
                template = env.get_template('no_partner.html')
                return template.render({})

        template = env.get_template("binding.html")
        return template.render({
            'session': request.session,
            'mobile': mobile,
            'partner': partner,
            'address_contacts': address_contacts,
            'user': user,
            'attention': request.session.get('status', 0) == 1 and True or False,
        })

    def _prepare_user_vals(self, partner, oauth_uid):
        vals = {
            'name': partner.name,
            'login': oauth_uid,
            'partner_id': partner.id,
        }

        if partner.is_company:
            vals.update({
                'sel_groups_5': False,
                'in_group_1': True,
            })

        return vals

    # @正翔 微信用户绑定操作
    # @张旭 每个微信用户都对应一个user，但同一个企业的user的partner_id都相同，user根据手机号码查找
    @http.route('/weixin/do_binding', auth='public')
    def do_binding(self, user_id, **kw):
        db_name = request.session.db
        db = RegistryManager.get(db_name)
        if not user_id:
            return '{}'

        context = {}
        with closing(db.cursor()) as cr:
            contacts_obj = openerp.registry(db_name)['weixin.contacts']
            user_obj = openerp.registry(db_name)['res.users']
            try:
                contacts = contacts_obj.browse(cr, SUPERUSER_ID, int(user_id), context=context)
            except ValueError:
                return '{}'
            if not contacts.odoo_user_id:
                odoo_user_id = user_obj.create(cr, SUPERUSER_ID, self._prepare_user_vals(contacts.partner_id,
                                                                                         request.session.oauth_uid or user_id),
                                               context=context)
                odoo_user = user_obj.browse(cr, SUPERUSER_ID, odoo_user_id, context=context)
            else:
                odoo_user = contacts.odoo_user_id

            weixin_data = user_obj.auth_oauth_get_weixin(cr, SUPERUSER_ID, request.session.oauth_provider_id,
                                                         request.session.access_token, user_id, context=context)

            odoo_user.write({
                'oauth_uid': request.session.oauth_uid,
                'oauth_access_token': request.session.oauth_access_token,
                'oauth_provider_id': request.session.oauth_provider_id,
                'mobile': contacts.mobile,
                'weixin_id': weixin_data.get('weixinid'),
            })

            contacts.write({'is_follow': True, 'weixinid': weixin_data.get('weixinid'), 'odoo_user_id': odoo_user.id})

            cr.commit()
            uid = request.session.authenticate(db_name, odoo_user.login, request.session.oauth_access_token)
            return simplejson.dumps({
                'partner_id': contacts.partner_id.id,
                'uid': uid,
                'login_id': request.session.oauth_uid,
                'is_exists_mobile': True,
                'oauth_access_token': request.session.oauth_access_token,
                'user_id': user_id,
                'mobile': contacts.mobile,
                'access_token': request.session.access_token,
            })

    @http.route('/weixin/old/do_binding', auth='public')
    def do_binding_old(self, mobile, **kw):
        db_name = request.session.db
        db = RegistryManager.get(db_name)
        if not mobile:
            return '{}'

        context = {}
        with closing(db.cursor()) as cr:
            partner_obj = openerp.registry(db_name)['res.partner']
            address_obj = openerp.registry(db_name)['customer.address']
            user_obj = openerp.registry(db_name)['res.users']

            user = None
            partner = None
            address = None

            exits_user_ids = user_obj.search(cr, SUPERUSER_ID,
                                             [('oauth_uid', '=', request.session.oauth_uid or mobile)], limit=1,
                                             context=context)
            if exits_user_ids:
                user = user_obj.browse(cr, SUPERUSER_ID, exits_user_ids[0])
                partner = user.partner_id
            else:
                partner_ids = partner_obj.search(cr, SUPERUSER_ID, [('mobile', '=', mobile)], limit=1, context=context)
                if partner_ids:
                    partner = partner_obj.browse(cr, SUPERUSER_ID, partner_ids[0])

                if not partner or partner.is_company:
                    address_ids = address_obj.search(cr, SUPERUSER_ID, [('mobile_number', '=', mobile)], limit=1,
                                                     context=context)
                    if address_ids:
                        address = address_obj.browse(cr, SUPERUSER_ID, address_ids[0], context=context)
                        partner = address.partner_id

                if not partner:
                    return simplejson.dumps({
                        'no_partner': True,
                    })
                if partner.user_ids:
                    user = partner.user_ids[0]
                else:
                    user_id = user_obj.create(cr, SUPERUSER_ID,
                                              self._prepare_user_vals(partner, request.session.oauth_uid or mobile),
                                              context=context)
                    user = user_obj.browse(cr, SUPERUSER_ID, user_id, context=context)

            if address:
                address.write({'user_id': user.id})

                # partner_id = None
                # partner = None
                # address = None
                # partner_ids = partner_obj.search(cr, SUPERUSER_ID, [('mobile', '=', mobile)], limit=1, context=context)
                # if partner_ids:
                #     partner_id = partner_ids[0]
                #     partner = partner_obj.browse(cr, SUPERUSER_ID, partner_id)

                # #如果没有找到partner，或者partner找到了但是是企业客户，则进行多地址联系人的手机号码查找
                # if not partner_id or (partner_id and partner.is_company):
                #     address_ids = address_obj.search(cr, SUPERUSER_ID, [('mobile_number', '=', mobile)], limit=1, context=context)
                #     if address_ids:
                #         address = address_obj.browse(cr, SUPERUSER_ID, address_ids[0], context=context)
                #         partner = address.partner_id
                #         partner_id = address.partner_id.id

                # #从res.partner找到了对应的partner或者通过多地址找到了partner，都可以继续绑定
                # if partner:
                #     #查找是否存在user
                #     exits_user_ids = user_obj.search(cr, SUPERUSER_ID, [('oauth_uid', '=', mobile)], context=context)
                #     if exits_user_ids:
                #         user_id = exits_user_ids[0]
                #     else:
                #         # 使用request.session.oauth_uid来作为用户的login？
                #         user_id = user_obj.create(cr, SUPERUSER_ID, self._prepare_user_vals(partner, request.session.oauth_uid), context=context)
                #     # 如果存在多地址联系人，则将多地址的联系人关联上user
                #     if address:
                #         address.write({'user_id': user_id})
                # is_share_user = False
                # if partner.is_company:
                #     is_share_user = True
                # 保存用户相关微信登录信息

            user.write({
                'partner_id': partner and partner.id,
                'oauth_uid': request.session.oauth_uid,
                'oauth_access_token': request.session.oauth_access_token or mobile,
                'oauth_provider_id': request.session.oauth_provider_id,
                'mobile': mobile,
                'weixin_id': request.session.weixin_id,
                # 'share': is_share_user
            })

            cr.commit()
            uid = request.session.authenticate(db_name, user.login, request.session.oauth_access_token or mobile)
            return simplejson.dumps({
                'partner_id': partner and partner.id,
                'uid': uid,
                'login_id': request.session.oauth_uid,
                'is_exists_mobile': True,
                'oauth_access_token': request.session.oauth_access_token,
                'user_id': request.session.user_id,
                'access_token': request.session.access_token,
            })

            # return simplejson.dumps({'is_exists_mobile': False})

    # @http.route('/weixin/do_binding', auth='public')
    # def do_binding(self, **kw):
    #     mobile = kw['mobile']
    #     auth_code = kw['auth_code']
    #     db_name = request.session.db
    #     db = RegistryManager.get(db_name)
    #     partner_id = ''
    #     uid = ''
    #     login_id = ''
    #     oauth_access_token = ''
    #     if not mobile:
    #         return '{}'

    #     with closing(db.cursor()) as cr:
    #         res_partner = openerp.registry(db_name)['res.partner']
    #         mobile_partner_ids = res_partner.search(cr, SUPERUSER_ID, [('mobile', '=', mobile)])
    #         if mobile_partner_ids:
    #             is_exists_mobile = True
    #             partner_id = mobile_partner_ids[0]
    #             #根据partner找到用户
    #             res_users = openerp.registry(db_name)['res.users']
    #             users_ids = res_users.search(cr, SUPERUSER_ID, [('partner_id', '=', partner_id)])
    #             if users_ids:
    #                 user_row = res_users.browse(cr, SUPERUSER_ID, users_ids[0])
    #                 oauth_uid = request.session.oauth_uid
    #                 oauth_access_token = request.session.oauth_access_token
    #                 oauth_provider_id = request.session.oauth_provider_id
    #                 weixin_id = request.session.weixin_id
    #                 login_id = user_row.login
    #                 #写入绑定
    #                 user_row.write({'oauth_uid': oauth_uid, 'oauth_access_token': oauth_access_token,
    #                                 'oauth_provider_id': oauth_provider_id, 'mobile': mobile, 'weixin_id': weixin_id})
    #                 cr.commit()
    #                 #进行登录
    #                 uid = request.session.authenticate(db_name, login_id, oauth_access_token)
    #         else:
    #             is_exists_mobile = False
    #     #template = env.get_template("binding_result.html")
    #     return simplejson.dumps({'partner_id': partner_id, 'uid': uid, 'login_id': login_id,
    #                              'is_exists_mobile': is_exists_mobile, 'oauth_access_token': oauth_access_token})
    # 微信用户取消绑定操作
    @http.route('/weixin/do_cancel_binding', auth='user')
    def do_cancel_binding(self, **kw):
        db_name = request.session.db
        db = RegistryManager.get(db_name)
        result = ''
        with closing(db.cursor()) as cr:
            res_users = openerp.registry(db_name)['res.users']
            # address_obj = openerp.registry(db_name)['customer.address']

            user_ids = res_users.search(cr, SUPERUSER_ID, [('id', '=', request.session.uid)])
            if user_ids:
                user_row = res_users.browse(cr, SUPERUSER_ID, user_ids[0])
                user_row.write({'oauth_access_token': None, 'oauth_uid': None,
                                'oauth_provider_id': None, 'mobile': None, 'weixin_id': None})
                request.session.logout(keep_db=True)
                result = 'OK'

                # if kw.get('address_id'):
                # address_obj.write(cr, SUPERUSER_ID, int(kw.get('address_id')), {'user_id': False})

            cr.commit()

        return simplejson.dumps({'result': result})

    @http.route('/weixin/point_qrcode', auth='public')
    def point_qrcode(self, type, point_events_id, url, width=600, height=100):
        """Contoller able to render barcode images thanks to reportlab.
        Samples:
            <img t-att-src="'/report/barcode/QR/%s' % o.name"/>
            <img t-att-src="'/report/barcode/?type=%s&amp;value=%s&amp;width=%s&amp;height=%s' %
                ('QR', o.name, 200, 200)"/>

        :param type: Accepted types: 'Codabar', 'Code11', 'Code128', 'EAN13', 'EAN8', 'Extended39',
        'Extended93', 'FIM', 'I2of5', 'MSI', 'POSTNET', 'QR', 'Standard39', 'Standard93',
        'UPCA', 'USPS_4State'
        """

        try:
            db_name = request.session.db
            width, height = int(width), int(height)
            url = 'http://' + request.httprequest.host + url
            barcode = createBarcodeDrawing(
                type, value=url, format='png', width=width, height=height
            )
            barcode = barcode.asString('png')
        except (ValueError, AttributeError):
            raise openerp.exceptions.HTTPException(description='Cannot convert into barcode.')
        return request.make_response(barcode, headers=[('Content-Type', 'image/png')])

    def weixin_sig_out_logic(self, cr, uid, pool, kw, context):
        now_time = datetime.datetime.now(pytz.timezone("UTC"))
        shanghai_time = datetime.datetime.now(pytz.timezone("Asia/Shanghai"))
        check_in_sign_id_c = pool.get('check.in.sign').search(cr, uid,
                                                              [('check_in_uid', '=', uid),
                                                               ('check_in_time', '<', shanghai_time.strftime('%Y-%m-%d 16:00:00')),
                                                               ('check_in_time', '>=', (shanghai_time + datetime.timedelta(
                                                                   days=-1)).strftime('%Y-%m-%d 16:00:00'))],
                                                              order='check_in_time desc', limit=1,
                                                              context=context)
        # 查找当天的签到记录
        check_in_sign_id = pool.get('check.in.sign').search(cr, uid,
                                                            [('check_in_uid', '=', uid),
                                                             ('is_check_out', '=', False),
                                                             ('check_out_time', '=', False),
                                                             ('check_in_time', '<', shanghai_time.strftime('%Y-%m-%d 16:00:00')),
                                                             ('check_in_time', '>=', (shanghai_time + datetime.timedelta(
                                                                 days=-1)).strftime('%Y-%m-%d 16:00:00'))],
                                                            order='check_in_time desc', limit=1, context=context)
        state = 'success'
        message = u'签出成功'
        point_messge = ''
        if check_in_sign_id:
            check_in_sign_objs = pool.get('check.in.sign').browse(cr, uid, check_in_sign_id[0], context=context)
            check_in_time_currcy = datetime.datetime.strptime(check_in_sign_objs.check_in_time, "%Y-%m-%d %H:%M:%S")
            create_date_time = time.strptime(kw.get('sign_out_time'), ISODATETIMEFORMAT)
            check_out_time_currcy = datetime.datetime(*create_date_time[:3])
            check_in_sign_objs.write(
                {'is_check_out': True, 'check_out_time': now_time.strftime(ISODATETIMEFORMAT),
                 'sign_out_latitude': kw.get('latitude'),'sign_out_longitude': kw.get('longitude'),
                 'stay_minutes': ((check_out_time_currcy - check_in_time_currcy).seconds) / 60, 'sign_out_reason':
                     (kw.get('sign_out_reason_list') == u'其他' and kw.get('sign_out_reason')) or (
                     kw.get('sign_out_reason_list') or kw.get('sign_out_reason') or u'正常下班')})
        else:
            #如果不存在签到记录,则新增签出记录
            #取得当前用户
            users_objs = pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context=context)
            # 查找当天的签出记录
            check_out_sign_id = pool.get('check.in.sign').search(cr, uid,
                                                            [('check_in_uid', '=', uid),
                                                             ('is_check_out', '=', True),
                                                             ('check_out_time', '<', shanghai_time.strftime('%Y-%m-%d 16:00:00')),
                                                             ('check_out_time', '>=', (shanghai_time + datetime.timedelta(
                                                                 days=-1)).strftime('%Y-%m-%d 16:00:00'))],
                                                            order='check_in_time desc', limit=1, context=context)
            # 如果已经有签出记录
            if check_out_sign_id:
                state = 'fail'
                message = u'签出失败'
                point_messge = u'签出失败，因为今天您已经签出过一次！'
            else:
                sign_out_reason = (kw.get('sign_out_reason_list') == u'其他' and kw.get('sign_out_reason')) \
                    or (kw.get('sign_out_reason_list') or kw.get('sign_out_reason') or u'正常下班')
                pool.get('check.in.sign').create(cr, uid,
                                                     {'employee_id': users_objs.employee_ids[0].id, 'check_in_uid': uid,
                                                      'is_check_out': True,
                                                      'check_out_time': now_time.strftime(ISODATETIMEFORMAT),
                                                      'sign_out_latitude': kw.get('latitude'),
                                                      'sign_out_longitude': kw.get('longitude'),
                                                      'sign_out_reason': sign_out_reason},
                                                     context=context)
        # else: #未签到也允许签出
        #     state = 'fail'
        #     message = '签出失败！'
        #     point_messge = '签出失败，因为今天您没有签到过！'
        event_id = pool.get('point.events').search(cr, uid, [('event_code', '=', 'SIGN_OUT')], context=context)
        if event_id and not check_in_sign_id_c:
            events_message_list = pool.get('point.events').payment_point(cr, uid, event_id, context=context)
            point_messge = "%s %s" % (point_messge, (events_message_list))
        return (state, message, point_messge)

    def rad(self, flo):
        return flo * math.pi / 180.0

    def calcu_distance(self, lat1, lng1, lat2, lng2):
        earth_radius = 6378.137
        radlat1 = self.rad(lat1)
        radlat2 = self.rad(lat2)
        a = radlat1 - radlat2
        b = self.rad(lng1) - self.rad(lng2)
        s = 2 * math.asin(math.sqrt(
            math.pow(math.sin(a / 2), 2) + math.cos(radlat1) * math.cos(radlat2) * math.pow(math.sin(b / 2), 2)))
        s = s * earth_radius
        if s < 0:
            return round(-s, 4)
        else:
            return round(s, 4)

    @http.route('/weixin/sign/out', auth='weixin')
    def weixin_sig_out(self, **kw):
        cr, uid, context, pool = request.cr, request.session.uid, request.context, request.registry
        # 微信扫码，签到失败（时区问题）（微信认证登陆，获取不到context中的时区问题）--解决方案，暂时强制写入上海时区
        # now_time = datetime.datetime.now(pytz.timezone("UTC"))
        shanghai_time = datetime.datetime.now(pytz.timezone("Asia/Shanghai"))
        sgin_message = self.weixin_app.get_jsapi_signature(cr, uid, pool, context)
        template = env.get_template('point_events_state.html')
        event_id = pool.get('point.events').search(cr, SUPERUSER_ID, [('event_code', '=', 'SIGN_OUT'), ('is_active', '=', True)], context=context)
        users_objs = pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context=context)
        sign_out_reason = (kw.get('sign_out_reason_list') and kw.get('sign_out_reason_list') != 'none' and kw.get('sign_out_reason_list') != '其他') or kw.get('sign_out_reason')
        if (not sign_out_reason) and kw.get('user'):
            return template.render({'state': 'no_reson', 'message': u'在工作时间内外出必须填写外出理由！', 'title': u'签出失败！'})
        distance = self.calcu_distance(float(kw.get('longitude', 0)), float(kw.get('latitude', 0)), 121.534355,
                                       31.331444)
        if kw.get('latitude') and kw.get('longitude') or sign_out_reason:
            if abs(distance) or sign_out_reason: # abs(distance) *1000 <= 100 or  签出的业务逻辑有所调整，目前不判断是否在公司
                if event_id:
                    event_objs = pool.get('point.events').browse(cr, SUPERUSER_ID, event_id, context=context)
                    if event_id and event_objs and event_objs.group_ids and not any(
                            [(group_objs.id in [groups.id for groups in users_objs.groups_id]) for group_objs in
                             event_objs.group_ids]):
                        state = 'fail'
                        message = u"签出失败!"
                        point_messge = u'您不能参加签到！'
                    elif sign_out_reason or kw.get('sign_out_time') > shanghai_time.strftime('%Y-%m-%d 17:30:00'):
                        state, message, point_messge = self.weixin_sig_out_logic(cr, uid, pool, kw, context)
                    else:
                        state = 'sign_out_reason'
                        point_messge = ''
                        message = ''
                else:
                    state = 'fail'
                    point_messge = '签出失败!'
                    message = '签出活动已取消!'
            else:
                state = 'faill'
                point_messge = '您不再公司！'
                message = '不能进行开签出！'
            return_message = {'state': state,
                              'title': u'签出信息',
                              'message': message,
                              'latitude': kw.get('latitude'),
                              'longitude': kw.get('longitude'),
                              'sign_out_time':shanghai_time.strftime(ISODATETIMEFORMAT),
                              'point_messge': point_messge
                              }
            if kw.get('user'):
                return template.render(return_message)
            return request.make_response(simplejson.dumps(return_message))
        else:
            state = ''
            message = ''
            point_messge = ''
        return_message = {'state': state,
                          'title': u'签到信息',
                          'name': users_objs.partner_id.name or '',
                          'url': '/weixin/sign/out',
                          'message': message,
                          'point_messge': point_messge,
                          'sign_out_time':shanghai_time.strftime(ISODATETIMEFORMAT),
                          }
        return_message.update(sgin_message)
        return template.render(return_message)

    def weixin_sign_in_logic(self, cr, uid, pool, event_id, latitude, longitude, context):
        users_objs = pool.get('res.users').browse(cr, uid, uid, context=context)
        now_time = datetime.datetime.now(pytz.timezone("UTC"))
        shanghai_time = datetime.datetime.now(pytz.timezone("Asia/Shanghai"))
        check_in_sign_id = pool.get('check.in.sign').search(cr, uid,
                                                            [('check_in_uid', '=', uid), ('is_check_out', '=', False),
                                                             ('check_out_time', '=', False),
                                                             ('check_in_time', '<', shanghai_time.strftime('%Y-%m-%d 16:00:00')),
                                                             ('check_in_time', '>=', (shanghai_time + datetime.timedelta(
                                                                 days=-1)).strftime('%Y-%m-%d 16:00:00'))],
                                                            order='check_in_time desc', limit=1, context=context)

        if not check_in_sign_id:
            check_in_sign_id_c = pool.get('check.in.sign').search(cr, uid,
                                                                  [('check_in_uid', '=', uid),
                                                                   ('check_in_time', '<', shanghai_time.strftime('%Y-%m-%d 16:00:00')),
                                                                   ('check_in_time', '>=', (shanghai_time + datetime.timedelta(
                                                                       days=-1)).strftime('%Y-%m-%d 16:00:00'))],
                                                                  order='check_in_time desc', limit=1, context=context)
            if users_objs.employee_ids:
                pool.get('check.in.sign').create(cr, uid,
                                                 {'employee_id': users_objs.employee_ids[0].id, 'check_in_uid': uid,
                                                  'check_in_time': now_time.strftime(ISODATETIMEFORMAT),
                                                  'latitude': latitude, 'longitude': longitude},
                                                 context=context)
                events_message_list = ''
                if event_id and not check_in_sign_id_c and shanghai_time.strftime(ISODATETIMEFORMAT) < shanghai_time.strftime('%Y-%m-%d 08:30:00'):
                    events_message_list = pool.get('point.events').payment_point(cr, uid, event_id, context=context)
                state = 'success'
                message = u"签入成功!"
                point_messge = events_message_list
            else:
                state = 'fail'
                message = u"签入失败!"
                point_messge = u"您的员工关联用户填写有误!"
        else:
            state = 'fail'
            message = u"签入失败!"
            point_messge = u'您今天有一次没有签出的签入记录,请签出后再进行操作!'
        return (state, message, point_messge)

    @http.route('/weixin/sign/in_check_location', auth='weixin')
    def weixin_in_check_location(self, **kw):
        cr, uid, context, pool = request.cr, request.session.uid, request.context, request.registry
        # 微信扫码，签到失败（时区问题）（微信认证登陆，获取不到context中的时区问题）--解决方案，暂时强制写入上海时区
        distance = self.calcu_distance(float(kw.get('longitude', 0)), float(kw.get('latitude', 0)), 121.534355,
                                       31.331444)

        if kw.get('latitude') and kw.get('longitude'):
            if abs(distance) *1000 <= 100:       # distance 返回结果的单位是公里 ，乘 1000 换算成米 坐标与基准坐标相差 100米
                event_id = pool.get('point.events').search(cr, uid, [('event_code', '=', 'SIGN_IN'), ('is_active', '=', True)], context=context)
                users_objs = pool.get('res.users').browse(cr, uid, uid, context=context)
                if event_id:
                    event_objs = pool.get('point.events').browse(cr, SUPERUSER_ID, event_id, context=context)

                    if event_id and event_objs and event_objs.group_ids and not any([(group_objs.id in [groups.id for groups in users_objs.groups_id]) for group_objs in event_objs.group_ids]):
                        state = 'fail'
                        message = u"签入失败!"
                        point_messge = u'您不能参加签到！'
                    # elif remote_addr not in ['112.64.141.214', '101.226.125.113', '127.0.0.1']:
                    #     state = 'fail'
                    #     message = u"签入失败!"
                    #     point_messge = u'您的IP为%s，请使用公司的WI-FI网络！' % (remote_addr,)
                    else:
                        state, message, point_messge = self.weixin_sign_in_logic(cr, uid, pool, event_id, kw.get('latitude'), kw.get('longitude'), context)
                else:
                    state = 'fail'
                    message = u"签入失败!"
                    point_messge = u'活动已取消！'
            else:
                state, message, point_messge = 'location_erro', '您不在公司不能进行签到！', ''
        else:
            state, message, point_messge = '', '获取您的地理位置信息失败！', '请检查网络链接，重新扫码签入！'
        return_message = {'state': state,
                          'title': u'签到信息',
                          'url': '/weixin/sign/in_check_location',
                          'message': message,
                          'point_messge': point_messge}
        return request.make_response(simplejson.dumps(return_message))

    @http.route('/weixin/sign/in', auth='weixin')
    def weixin_sig_in(self, **kw):
        cr, uid, context, pool = request.cr, request.session.uid, request.context, request.registry
        template = env.get_template('point_events_state.html')
        # 微信扫码，签到失败（时区问题）（微信认证登陆，获取不到context中的时区问题）--解决方案，暂时强制写入上海时区
        sgin_message = self.weixin_app.get_jsapi_signature(cr, uid, pool, context)
        message = {'state': '',
                   'title': u'签到信息',
                   'url': '/weixin/sign/in_check_location',
                   'message': '',
                   'point_messge': ''}
        message.update(sgin_message)
        return template.render(message)

